package com.grj.service.redis.controller;


import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.grj.service.redis.entity.User;
import com.grj.service.redis.service.MyService;
import com.grj.service.redis.service.UserService;
import com.grj.service.redis.service.impl.RedisIdWorker;
import io.micrometer.core.instrument.util.JsonUtils;
import lombok.RequiredArgsConstructor;
import org.redisson.RedissonIdGenerator;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author 14505
 */
@RestController
@RequestMapping("/post")
@RequiredArgsConstructor
public class PostController<T> {

    private final UserService userService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private RedisIdWorker redisIdWorker;

    @GetMapping
    public List<User> list() {
        Map<Object, Object> userList = redisTemplate.opsForHash().entries("userList");
        if(userList.size() == 0){
            List<User> list = userService.list();
            list.forEach(user -> userList.put(user.getId(),user));
            redisTemplate.opsForHash().putAll("userList", userList);
            return list;
        }
        return userList.keySet().stream().map(k -> {
            User user = new User();
            user.setId(Integer.valueOf(k.toString()));
            user.setName(userList.get(k).toString());
            return user;
        }).collect(Collectors.toList());
    }

    @GetMapping("/page/{id}")
    public List<Object> test(@PathVariable Integer id) {
        Page<User> page = userService.page(new Page<>(id, 10),new LambdaQueryWrapper<User>().select(User::getId).orderByDesc(User::getId));
        return redisTemplate.opsForHash().multiGet("userList", page.getRecords().stream().map(User::getId).collect(Collectors.toList()));
    }
    @GetMapping("id/{id}")
    public Object test2(@PathVariable Integer id) {
        Object userList = redisTemplate.opsForHash().get("userList", id);
        if(userList == null){
            User user = userService.getById(id);
            redisTemplate.opsForHash().put("userList", id, user);
            return user;
        }
        return redisTemplate.opsForHash().get("userList", id);
    }

    @GetMapping("data")
    public Boolean user(){
        List<User> objects = new ArrayList<>();
        for (int i = 3; i <=100000; i++) {
            User user = new User();
            user.setId(i);
            user.setName("user"+i);
            objects.add(user);
        }
        return userService.saveBatch(objects);
    }

    @GetMapping("/cache/{id}")
    public List<User> test1(@PathVariable Integer id) {
        List<User> list = userService.page(new Page<>(id, 10000)).getRecords();
        HashMap<Object, Object> map = new HashMap<>();
        for (User user : list) {
            map.put(user.getId(), user);
        }
        redisTemplate.opsForHash().putAll("userList",  map);
        return list;
    }

    @GetMapping("/clear")
    public Boolean clear(){
        redisTemplate.delete("userList");
        return true;
    }

    @GetMapping("/redisson")
    public String redisson(){
        toLock(() -> {
            TimeUnit.SECONDS.sleep(10);
            return null;
        });
        return "ol";
    }

    void toLock(MyService<String> myService){
        RLock lock = redissonClient.getLock("vehicle-lock");
        System.out.println("当前线程:" + Thread.currentThread().getName());
        //加锁
        try {
            if (!lock.tryLock(1, TimeUnit.SECONDS)) {
                String message = "线程:" + Thread.currentThread().getName() + "未获取到锁,直接返回";
                System.out.println(message);
                return;
            }
            System.out.println("线程:" + Thread.currentThread().getName() + "获取到锁!");
            myService.toLock();
            System.out.println("线程:" + Thread.currentThread().getName() + "业务结束!");
        } catch (InterruptedException e) {
            throw new RuntimeException(String.format("出现异常：%s",e.getMessage()));
        } finally {
            //判断 拿到了锁的才释放锁,否则会报错!
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                System.out.println("线程:" + Thread.currentThread().getName() + "释放锁!");
                lock.unlock();
            }
        }
    }

    @GetMapping("redisson2")
    public void redisson2(){
        Date date = new Date();
        long time = date.getTime();
        User user = new User();
        user.setExpire(new Date(time+1000));
        String s = JSONUtil.toJsonStr(user);
        redisTemplate.opsForValue().set("key", s);
        System.out.println(time);
    }

    @GetMapping("redisson3/{id}")
    public void redisson3(@PathVariable Integer id){
        Date date = new Date();
        long time = date.getTime();
        User user = userService.getById(id);
        user.setExpire(new Date(time + 10*1000));
        redisTemplate.opsForValue().set("key:"+id,JSONUtil.toJsonStr(user));
    }

    @GetMapping("redisson4/{id}")
    public User redisson4(@PathVariable Integer id){
        Object key = redisTemplate.opsForValue().get("key:"+id);
        if(key == null){
            return null;
        }
        User user = JSONUtil.toBean(key.toString(), User.class);

        if(user.getExpire().getTime() < System.currentTimeMillis()){
            redisTemplate.delete("key:"+id);
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new ThreadPoolExecutor.AbortPolicy());
            threadPoolExecutor.execute(() -> redisson3(1));
            threadPoolExecutor.shutdown();
            user.setName("过期了==============================================================");
            System.out.println(new Date()+"=====================过期了==============================================================");
            return user;
        }
        return user;
    }

    @GetMapping("uuid")
    public void uuid() throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(300);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(500, 500, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new ThreadPoolExecutor.AbortPolicy());
        long l = System.currentTimeMillis();
        System.out.println(l);
        for (int i = 0; i < 300; i++) {
            executor.execute(() -> {
                long order = redisIdWorker.nextId("order");
                System.out.println(order);
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        System.out.println(System.currentTimeMillis() - l);
        System.out.println("ok");
    }
}
